/*
 * Copyright (C) 2024 pedroSG94.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.pedro.streamer.file

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.graphics.Color
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.MotionEvent
import android.view.View
import android.view.View.OnTouchListener
import android.view.WindowManager
import android.widget.EditText
import android.widget.ImageView
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import com.pedro.common.ConnectChecker
import com.pedro.encoder.input.decoder.AudioDecoderInterface
import com.pedro.encoder.input.decoder.VideoDecoderInterface
import com.pedro.encoder.input.gl.render.filters.`object`.TextObjectFilterRender
import com.pedro.encoder.utils.gl.TranslateTo
import com.pedro.library.generic.GenericFromFile
import com.pedro.library.view.OpenGlView
import com.pedro.streamer.R
import com.pedro.streamer.utils.FilterMenu
import com.pedro.streamer.utils.ScreenOrientation
import com.pedro.streamer.utils.toast
import com.pedro.streamer.utils.updateMenuColor
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.io.IOException

/**
 * Example code to stream using a file.
 * Necessary API 18+
 *
 */
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
class FromFileActivity : AppCompatActivity(),OnTouchListener, ConnectChecker,
  VideoDecoderInterface, AudioDecoderInterface, OnSeekBarChangeListener {

  private lateinit var genericFromFile: GenericFromFile
  private lateinit var bStream: ImageView
  private lateinit var bSelectFile: ImageView
  private lateinit var etUrl: EditText
  private lateinit var openGlView: OpenGlView

  private val filterMenu: FilterMenu by lazy { FilterMenu(this) }
  private var currentFilter: MenuItem? = null
  private var pushUrl="rtmp://127.0.0.1:1935/file/live"

  private val circularLinkedList:CircularLinkedList<Uri> by lazy { CircularLinkedList() }
  private var filePath: Uri? = null
  private var touching = false
  private var isconnected=false;
  private  var activityResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
    if (result.resultCode == Activity.RESULT_OK) {
      circularLinkedList.clear()
      result.data?.let { data ->
        val clipData = data.clipData
        if (clipData != null) {
          // 多个文件的情况
          for (i in 0 until clipData.itemCount) {
            val uri = clipData.getItemAt(i).uri
            if (i == 0) {
              filePath = uri
            }
            circularLinkedList.add(uri)
          }
        } else {
          // 单个文件的情况
          data.data?.let { uri ->
            filePath = uri
            circularLinkedList.add(uri)
          }
        }
      }
    }
  }

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
    setContentView(R.layout.activity_from_file)

    bStream = findViewById(R.id.b_start_stop)
    bSelectFile = findViewById(R.id.select_file)
    etUrl = findViewById(R.id.et_rtp_url)
    openGlView = findViewById(R.id.surfaceView)
    val textObjectFilterRender = TextObjectFilterRender()
    openGlView.addFilter(0,textObjectFilterRender)
    textObjectFilterRender.setText("这是一个水印", 12f, Color.RED,Color.WHITE)
    textObjectFilterRender.setPosition(TranslateTo.LEFT)
    textObjectFilterRender.setAlpha(0.5f)
    textObjectFilterRender.left2right=true
    textObjectFilterRender.periodX=10f

    genericFromFile = GenericFromFile(openGlView, this, this, this)
    genericFromFile.getStreamClient().setReTries(3)//设置重试次数 3次，一般情况下本地除非rtmp端口占用，一般不会连接不上。


    bStream.setOnClickListener {
      if (genericFromFile.isStreaming) {
        stopPlayAndPush()
        if (!genericFromFile.isRecording) ScreenOrientation.unlockScreen(this)
      } else  {
        startPlayAndPush()
      }
    }

    bSelectFile.setOnClickListener {
      val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
        type = "*/*" // 选择所有类型的文件
        putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true) // 允许选择多个文件
      }
      activityResult.launch(intent)
    }

  }

  @RequiresApi(Build.VERSION_CODES.N)
  override fun onPause() {
    super.onPause()
    this.enterPictureInPictureMode()
  }

  override fun onDestroy() {
    super.onDestroy()

    genericFromFile.stopAudioDevice()
    if (genericFromFile.isStreaming) {
      genericFromFile.stopStream()
      bStream.setImageResource(R.drawable.stream_icon)
    }
    ScreenOrientation.unlockScreen(this)
    activityResult.unregister()
  }


  override fun onConnectionFailed(reason: String) {
    if (genericFromFile.getStreamClient().reTry(500, reason, null)) {
      toast("Retry")
    } else {
      toast("Failed: $reason")
      genericFromFile.stopStream()
      bStream.setImageResource(R.drawable.stream_icon)
      if (!genericFromFile.isRecording) ScreenOrientation.unlockScreen(this)
    }
  }

  override fun onNewBitrate(bitrate: Long) {}
  override fun onConnectionStarted(url: String) {}

  override fun onConnectionSuccess() {
    isconnected=true
    toast("Connected")
  }

  override fun onDisconnect() {
    isconnected=false;
    toast("Disconnected")
  }

  override fun onAuthError() {
    toast("Auth error")
    genericFromFile.stopStream()
    bStream.setImageResource(R.drawable.stream_icon)
    if (!genericFromFile.isRecording) ScreenOrientation.unlockScreen(this)
  }

  override fun onAuthSuccess() {
    toast("Auth success")
  }

  @Throws(IOException::class)
  private fun prepare(): Boolean {
    if (filePath == null) return false
    var result = genericFromFile.prepareVideo(applicationContext, filePath)
    result = result or genericFromFile.prepareAudio(applicationContext, filePath)
    return result
  }

  private fun startPlayAndPush() {
    if (genericFromFile.isRecording || prepare()) {
//      if (!genericFromFile.isAudioDeviceEnabled) genericFromFile.playAudioDevice()//这不需要播放音频，远端拉流在播放，避免两个播放器都播放音频
      genericFromFile.startStream(pushUrl)
      bStream.setImageResource(R.drawable.stream_stop_icon)
      ScreenOrientation.lockScreen(this)
    }else {
      toast("Error preparing stream, This device cant do it")
    }
  }
  private fun stopPlayAndPush(){
//    genericFromFile.stopAudioDevice()//这不需要播放音频，远端拉流在播放，避免两个播放器都播放音频
    if (genericFromFile.isStreaming) {
      genericFromFile.stopStream()
      bStream.setImageResource(R.drawable.stream_icon)
    }
  }


  override fun onCreateOptionsMenu(menu: Menu): Boolean {
    menuInflater.inflate(R.menu.filter, menu)
    val defaultFilter = menu.findItem(R.id.no_filter)

    currentFilter = defaultFilter.updateMenuColor(this, currentFilter)
    return true
  }

  override fun onOptionsItemSelected(item: MenuItem): Boolean {
    try {
          val result = filterMenu.onOptionsItemSelected(item, openGlView)
          if (result) currentFilter = item.updateMenuColor(this, currentFilter)
          return result
    } catch (e: IllegalArgumentException) {
      toast("Change source error: ${e.message}")
    }
    return super.onOptionsItemSelected(item)
  }



  @SuppressLint("ClickableViewAccessibility")
  override fun onTouch(view: View, motionEvent: MotionEvent): Boolean {
    if (filterMenu.spriteGestureController.spriteTouched(view, motionEvent)) {
      filterMenu.spriteGestureController.moveSprite(view, motionEvent)
      filterMenu.spriteGestureController.scaleSprite(motionEvent)
      return true
    }
    return false
  }

  override fun onVideoDecoderFinished() {
    openGlView.post{
      stopPlayAndPush()
    }
    CoroutineScope(Dispatchers.IO).launch {
      filePath=circularLinkedList.getNext(filePath)
      while (isconnected){
        delay(30)
      }
      openGlView.post{
        startPlayAndPush()
      }
    }

  }
  override fun onAudioDecoderFinished() {

  }
  override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) {}
  override fun onStartTrackingTouch(seekBar: SeekBar) {
    touching = true
  }

  override fun onStopTrackingTouch(seekBar: SeekBar) {
    if (genericFromFile.isStreaming || genericFromFile.isRecording) {
      genericFromFile.moveTo(seekBar.progress.toDouble())
      //re sync after move to avoid async
      Handler(Looper.getMainLooper()).postDelayed({ genericFromFile.reSyncFile() }, 500)
    }
    touching = false
  }
}
